package core.helpers;

import io.appium.java_client.AppiumDriver;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.Platform;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.TestException;

import core.Config;
import core.Pilot;

public class MobDriverHelper extends DriverHelper
{

	public static Process appiumProcess = null;

	/**
	 * Initializes MobDriverHelper
	 * @param p_manager ApplicationManager instance
	 */
	public MobDriverHelper(Pilot p_manager)
	{
		super(p_manager);
	}

	private List<String> executeCommand(String p_command, Boolean p_wait)
	{

		List<String> result = new ArrayList<String>();

		try
		{
			appiumProcess = Runtime.getRuntime().exec(p_command);

			if (p_wait)
			{
				appiumProcess.waitFor();

				BufferedReader reader =
						new BufferedReader(new InputStreamReader(appiumProcess.getInputStream()));

				String line = "";
				while ((line = reader.readLine()) != null)
				{
					result.add(line);
				}
			}

		}
		catch (Exception p_ex)
		{
			throw new TestException("Exception while trying to Execute CMD / Shell Command : " + p_command + " : " + p_ex);
		}

		return result;

	}

	private Integer getAdbDevicesCount()
	{
		Integer res = 0;

		return res;
	}

	// #rem node node_modules\appium\bin\appium --port 4723 --bootstrap-port 4725 -U emulator-5554 --chromedriver-port
	// 9515
	private void startAppiumServer()
	{

		String tmpCmdl = null;

		try
		{

			tmpCmdl = "adb devices";
			List<String> adbOut = executeCommand(tmpCmdl, true);
			Integer adbDevicesCount = 0;

			// in order to Avoid a Failure finding of a 'device' Key in ADBs output's First line, as a sub-string of
			// 'devices' word
			if ((adbOut != null) && (adbOut.size() > 1))
			{
				adbOut.remove(0);
			}

			String tmpAdbDevice = null;

			if (pilot.dashboard().getAppiumUdid().length() > 0)
			{
				tmpAdbDevice = pilot.dashboard().getAppiumUdid();
			}
			else
			{

				for (String adbLine : adbOut)
				{
					pilot.log().info("ADB said : '" + adbLine + "'");
					if ((adbLine.contains("device")) || (adbLine.contains("emulator")))
					{
						adbDevicesCount++;
						tmpAdbDevice = adbLine.substring(0, adbLine.trim().indexOf('\t'));
						// break;
					}
				}
			}

			tmpCmdl = "adb.exe connect " + tmpAdbDevice;
			if (adbDevicesCount.equals(0))
			{
				pilot.log().info("Seems ADB doesnt know any devices connected... Re-init ADB with an appropriate device : " + tmpCmdl);
				executeCommand(tmpCmdl, false);
			}

			if (tmpAdbDevice != null)
			{
				tmpCmdl = "cmd /c cd "
						+ pilot.config().APPIUM_PATH
						+ " & cmd /c start node node_modules\\appium\\bin\\appium"
						+ " --port " + pilot.dashboard().getAppiumPort() // config().APPIUM_PORT
						+ " --bootstrap-port " + pilot.dashboard().getAppiumBootstrapPort() // manager.config().APPIUM_BOOTSTRAPPORT
						+ " -U " + pilot.dashboard().getAppiumUdid() // tmpAdbDevice
						+ " --chromedriver-port " + pilot.dashboard().getAppiumChromedriverPort(); // manager.config().APPIUM_CHROMEDRIVERPORT;

				pilot.log().info("Trying to start Appium Server with Commandline : " + tmpCmdl);
				executeCommand(tmpCmdl, false);

				pilot.log().info("Waiting Appium Server to start");
				Thread.sleep(24000);
			}
		}
		catch (Exception p_ex)
		{
			throw new TestException("Got Exception while trying to Initialize Appium Server : " + p_ex);
		}
	}

	/**
	 * Runs a local Android browser
	 */
	public boolean runLocalBrowser()
	{
		switch (pilot.dashboard().getServerType())
		{
			case Config.SERVER_LOCAL:
			{
				if (pilot.dashboard().getOS().equals(pilot.config().OS_ANDROID))
				{
					try
					{

						pilot.log().info("Appium settings :");
						pilot.log().info(pilot.config().APPIUM_DEVICE);
						pilot.log().info(pilot.config().APPIUM_BROWSER);
						pilot.log().info(pilot.config().APPIUM_PATH);
						pilot.log().info(pilot.dashboard().getAppiumPort());
						pilot.log().info(pilot.dashboard().getAppiumBootstrapPort());
						pilot.log().info(pilot.config().APPIUM_CHROMEDRIVER);
						pilot.log().info(pilot.dashboard().getAppiumChromedriverPort());
						pilot.log().info(pilot.dashboard().getAppiumUdid());
						pilot.log().info(pilot.config().APPIUM_LOG);
						pilot.log().info(pilot.config().APPIUM_LOGLEVEL);
						pilot.log().info(pilot.config().APPIUM_COMMANDTIMEOUT);

						startAppiumServer();

						DesiredCapabilities capabilities = new DesiredCapabilities();

						// CAPS for Appium Mode - Working
						// capabilities.setCapability("device", "Android");
						capabilities.setCapability("deviceName", "Android Emulator");
						capabilities.setCapability("platformName", "Android");

						capabilities.setCapability("app", "Browser");
						capabilities.setCapability(CapabilityType.BROWSER_NAME, pilot.config().APPIUM_BROWSER);
						capabilities.setCapability(CapabilityType.VERSION, "4.4");
						capabilities.setCapability(CapabilityType.PLATFORM, "WINDOWS");
						capabilities.setCapability("command-timeout", "120");
						capabilities.setCapability("newCommandTimeout", "999");

						capabilities.setCapability(CapabilityType.HAS_NATIVE_EVENTS, true);
						capabilities.setCapability(CapabilityType.SUPPORTS_JAVASCRIPT, true);
						// capabilities.setCapability(CapabilityType.HAS_TOUCHSCREEN, true);

						capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
						capabilities.setCapability(CapabilityType.ENABLE_PERSISTENT_HOVERING, true);
						capabilities.setCapability(CapabilityType.ENABLE_PROFILING_CAPABILITY, true);
						// capabilities.setCapability(CapabilityType.LOGGING_PREFS, "UNKNOWN");
						capabilities.setCapability(CapabilityType.ROTATABLE, true);
						capabilities.setCapability(CapabilityType.SUPPORTS_ALERTS, true);
						capabilities.setCapability(CapabilityType.SUPPORTS_APPLICATION_CACHE, true);
						capabilities.setCapability(CapabilityType.SUPPORTS_FINDING_BY_CSS, true);
						capabilities.setCapability(CapabilityType.SUPPORTS_LOCATION_CONTEXT, true);
						// capabilities.setCapability(CapabilityType.SUPPORTS_NETWORK_CONNECTION, true);
						capabilities.setCapability(CapabilityType.SUPPORTS_SQL_DATABASE, true);
						capabilities.setCapability(CapabilityType.SUPPORTS_WEB_STORAGE, true);
						capabilities.setCapability(CapabilityType.TAKES_SCREENSHOT, true);
						// capabilities.setCapability(CapabilityType.UNEXPECTED_ALERT_BEHAVIOUR, "UNKNOWS");

						URL tURL = new URL("http://127.0.0.1:" + pilot.dashboard().getAppiumPort() + "/wd/hub");
						driver = new AppiumDriver(tURL, capabilities);
						// driver = (SwipeableWebDriver) (new AppiumDriver(tURL, capabilities));
						// driver = new SwipeableWebDriver(tURL, capabilities);

						return true;
					}
					catch (Exception p_ex)
					{
						throw new TestException("Cannot start a Web browser driver: " + p_ex);
					}
				}
			}
			case Config.SERVER_SAUCELABS:
			{
				try
				{
					runRemoteBrowser();
					return true;
				}
				catch (Exception p_ex)
				{

					throw new TestException("Cannot start a Web browser driver: " + p_ex);
				}
			}
		}

		return false;
	}

	/**
	 * Runs a remote web browser on SauceLabs
	 * @param p_os OS name
	 * @param p_browser Browser name
	 * @param p_browserVersion Browser version
	 * @param p_proxy Proxy
	 * @param p_jobName Job name
	 */
	@SuppressWarnings("null")
	public void runRemoteBrowser(String p_os, String p_browser, String p_browserVersion, String p_proxy, String p_jobName)
	{
		DesiredCapabilities capabilities = null;// = getCapabilities(p_browser, p_proxy);

		// Set Browser Version
		if (p_browserVersion.equals("def"))
		{
			if (p_browser.equals(pilot.config().BROWSER_ANDROID))
			{
				capabilities = getCapabilities(p_browserVersion, p_proxy);
				capabilities.setCapability("version", pilot.config().BROWSER_ANDROID_VERSION);
				capabilities.setCapability("device-orientation", "portrait");

				capabilities.setCapability("command-timeout", 600);
				capabilities.setCapability("idle-timeout", 600);
			}
		}
		else
		{
			capabilities.setCapability("version", p_browserVersion);
		}

		// Set Job name
		capabilities.setCapability("name", p_jobName);

		// Set OS
		if (p_os.equals(pilot.config().OS_WIN_7))
		{
			capabilities.setCapability("platform", "Windows 7");
		}
		else if (p_os.equals(pilot.config().OS_WIN_8))
		{
			capabilities.setCapability("platform", Platform.WIN8);
		}
		else if (p_os.equals(pilot.config().OS_ANDROID))
		{
			capabilities.setCapability("platform", Platform.LINUX);
		}

		try
		{
			driver = new RemoteWebDriver(
					new URL("http://" + pilot.dashboard().getSaucelabsUsername() + ":" + pilot.dashboard().getSaucelabsKey()
							+ "@ondemand.saucelabs.com:80/wd/hub"),
					capabilities);
		}
		catch (Exception ex)
		{
			throw new TestException(ex.toString());
		}
	}

	/**
	 * Runs a remote browser on SauceLabs
	 */
	public void runRemoteBrowser()
	{
		runRemoteBrowser(pilot.dashboard().getOS(),
				pilot.dashboard().getBrowserName(),
				pilot.dashboard().getBrowserVersion(),
				pilot.dashboard().getProxy(),
				pilot.dashboard().getPlatform() + ":"
						+ pilot.dashboard().getTestName() + ":"
						+ pilot.dashboard().getSiteUrl() + ":"
						+ pilot.dashboard().getProxy() + ":"
						+ pilot.dashboard().getBrowserName() + "_"
						+ pilot.dashboard().getBrowserVersion());
	}

	/**
	 * Get desired capabilities
	 * @param p_browser
	 * @return
	 */
	@SuppressWarnings("static-access")
	private DesiredCapabilities getCapabilities(String p_browser, String p_proxy)
	{
		DesiredCapabilities capabilities = null;

		if (p_browser.equals(pilot.config().BROWSER_ANDROID))
		{
			capabilities = getAndroidOptions(p_proxy);
		}

		return capabilities;
	}

	/**
	 * Gets iPad options
	 * @param p_proxy Browser proxy
	 * @return DesiredCapabilities instance
	 */
	@SuppressWarnings("static-access")
	private DesiredCapabilities getIPadOptions(String p_proxy)
	{
		DesiredCapabilities capabilities = null;
		capabilities = new DesiredCapabilities().ipad();
		capabilities.setBrowserName("iPad");
		return capabilities;
	}

	/**
	 * Gets iPhone options
	 * @param p_proxy Browser proxy
	 * @return DesiredCapabilities instance
	 */
	@SuppressWarnings("static-access")
	private DesiredCapabilities getIPhoneOptions(String p_proxy)
	{
		DesiredCapabilities capabilities = null;
		capabilities = new DesiredCapabilities().ipad();
		capabilities.setBrowserName("iPhone");
		return capabilities;
	}

	/**
	 * Gets Android options
	 * @param p_proxy Browser proxy
	 * @return DesiredCapabilities instance
	 */
	@SuppressWarnings("static-access")
	private DesiredCapabilities getAndroidOptions(String p_proxy)
	{
		DesiredCapabilities capabilities = null;
		capabilities = new DesiredCapabilities().android();
		capabilities.setBrowserName("Android");
		return capabilities;
	}

	/**
	 * Used by mobile PO
	 * @param p_locator
	 */
	public void submit(By p_locator)
	{
		pilot.log().info("Submit Form via an element => [" + p_locator + "]");

		WebElement lElement = null;

		try
		{
			if (this.isElementDisplayed(p_locator))
			{

				scrollTo(p_locator);

				lElement = driver.findElement(p_locator);

				lElement.submit();
			}
		}
		catch (Exception p_ex)
		{
			throw new TestException("Cannot Submit a Form via an element => " + p_locator + "\nReason: " + p_ex);

		}
	}

}